package com.protocolmeter.STS;

import java.util.Arrays;

public class STAFunction {

	// public static void main(String[] args) {
	// STAFunction function = new STAFunction();
	//
	// String s1 = "11111111";
	//
	// // byte[] key = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
	// byte[] key = new byte[8];
	// for (int i = 0; i < 8; i++) {
	// int keyvalue = Integer.valueOf(s1.substring(i, i + 1));
	// key[i] = (byte) keyvalue;
	// }
	//
	// String data = function.getToken("00112233445566", key, true);
	// System.out.println(data);
	// }

	public String getToken(String data, byte[] key, boolean type) {
		if (type) {
			/**
			 * 加密
			 */
			// 1、7个字节数据 0-6
			byte[] token1 = new byte[data.length() / 2];
			for (int i = 0; i < token1.length; i++) {
				int value = Integer.valueOf(data.substring(i * 2, 2 + i * 2), 16);
				token1[token1.length - 1 - i] = (byte) value;
			}
			// 2、计算CRC
			int crc = this.checkout_crc(token1);

			// 3、保存CRC到数据字节中 保存到0-1，7个字节移到2-8
			byte[] token2 = new byte[9];
			System.arraycopy(token1, 0, token2, 2, 7);
			token2[0] = (byte) (crc & 0xFF);
			token2[1] = (byte) ((crc >> 8) & 0xff);
			// 4、STA加密 8个字节，0-7
			byte[] token3 = new byte[8];
			System.arraycopy(token2, 0, token3, 0, 8);
			byte[] token4 = new byte[8];
			this.STA(token3, token4, key, type);

			for (byte b : token4) {
				Integer.toHexString(b);
			}

			// 5、0-8个字节，27.28，64.65互换
			byte[] token5 = new byte[9];
			System.arraycopy(token4, 0, token5, 0, 8);
			token5[8] = token2[8];

			this.Class_get(token5);

			// 6、0-8转10进制
			byte[] token6 = new byte[20];
			this.HexToDec(token5, token6);
			// 7、返回10进制字符串
			String result = "";
			for (byte b : token6) {
				result += "0" + Byte.toString(b);
			}
			return result;
		} else {
			return null;
		}

	}

	// 超长数据乘16
	private static void Multi16(byte[] strSouce, byte[] strDest) {
		int i;
		int r, c;
		r = 0; // 进位
		c = 0; // 乘积

		for (i = 0; i < 20; i++) {
			c = (char) (strSouce[i] * 16);
			c += r;
			strDest[i] = (byte) (c % 10);
			r = (char) (c / 10);
		}
	}

	// 超长数据加
	private static void longadd(byte[] strSouce, byte val) {
		int i;
		int r, c;
		r = val; // 进位
		c = 0; // 和

		for (i = 0; i < 20; i++) {
			c = (char) (strSouce[i] + r);
			strSouce[i] = (byte) (c % 10);
			r = (char) (c / 10);
			if (r <= 0)
				break; // 没有进位，停止运算
		}
	}

	/**********************************************************
	 * 功能：超长16进制转换成10进制 参数1：strSouce，待转换的16进制数据 9bytes 参数2：strDest， 转换后的10进制数据
	 * 20bytes
	 **********************************************************/
	private void HexToDec(byte[] strSouce, byte[] strDest) {
		int i;
		int k = 0;
		int len;

		byte[] Souce = new byte[17];
		byte[] Dest = new byte[20];
		byte[] Dest1 = new byte[20];

		for (i = 8; i > 0; i--) {
			Souce[2 * i] = (byte) (strSouce[8 - i] & 0x0F);
			Souce[2 * i - 1] = (byte) (((strSouce[8 - i]) & 0xF0) >> 4);
		}
		Souce[0] = strSouce[8];
		len = 17;

		for (k = 0; k < len; k++) {
			Dest1 = Arrays.copyOf(Dest, Dest.length);
			Multi16(Dest1, Dest);
			longadd(Dest, Souce[k]);
		}
		for (i = 0; i < 20; i++)
			strDest[i] = Dest[19 - i];
	}

	// 28,29两位和65，66两位交换
	/************************************************************/
	private byte Class_get(byte[] DATA) {
		byte CLASS_NO;
		CLASS_NO = 0;
		CLASS_NO |= (byte) ((DATA[3] & 0X18) >> 3);

		if ((DATA[8] & 0X01) != 0)
			DATA[3] = (byte) (DATA[3] | 0X08);
		else
			DATA[3] = (byte) (DATA[3] & 0XF7);

		if ((DATA[8] & 0X02) != 0)
			DATA[3] = (byte) (DATA[3] | 0X10);
		else
			DATA[3] = (byte) (DATA[3] & 0XEF);

		DATA[8] = CLASS_NO;

		return CLASS_NO;

	}

	private static int crc_tab[] = { // CRC余式表
			0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241, 0XC601, 0X06C0, 0X0780, 0XC741, 0X0500,
			0XC5C1, 0XC481, 0X0440, 0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40, 0X0A00, 0XCAC1,
			0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841, 0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81,
			0X1A40, 0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41, 0X1400, 0XD4C1, 0XD581, 0X1540,
			0XD701, 0X17C0, 0X1680, 0XD641, 0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040, 0XF001,
			0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240, 0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0,
			0X3480, 0XF441, 0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41, 0XFA01, 0X3AC0, 0X3B80,
			0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840, 0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
			0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40, 0XE401, 0X24C0, 0X2580, 0XE541, 0X2700,
			0XE7C1, 0XE681, 0X2640, 0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041, 0XA001, 0X60C0,
			0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240, 0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480,
			0XA441, 0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41, 0XAA01, 0X6AC0, 0X6B80, 0XAB41,
			0X6900, 0XA9C1, 0XA881, 0X6840, 0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41, 0XBE01,
			0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40, 0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1,
			0XB681, 0X7640, 0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041, 0X5000, 0X90C1, 0X9181,
			0X5140, 0X9301, 0X53C0, 0X5280, 0X9241, 0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
			0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40, 0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901,
			0X59C0, 0X5880, 0X9841, 0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40, 0X4E00, 0X8EC1,
			0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41, 0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680,
			0X8641, 0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };

	private int checkout_crc(byte[] ptr) {
		byte i;
		int tmp, short_c;
		int crc = 0xffff;

		for (i = 0; i < 7; i++) // 校验7个字节
		{
			// short_c = 0x00ff & (char ) *ptr;
			short_c = 0x00ff & ptr[6 - i];
			tmp = crc ^ short_c;
			crc = (crc >> 8) ^ crc_tab[tmp & 0xff];
			// ptr --;
		}

		tmp = crc & 0xff00;
		crc = crc << 8;
		crc |= tmp >> 8;

		return crc & 0x00ffff;
	}

	/*************************************************************/

	// HX出厂模式
	/*
	 * const unsigned char HXDTTable1[16] = {12, 6, 2, 7, 13, 9, 5, 4, 1, 10,
	 * 14, 8, 0, 3, 15, 11};
	 */
	private static byte[] HXDTTable1 = new byte[] { 12, 6, 2, 7, 13, 9, 5, 4, 1, 10, 14, 8, 0, 3, 15, 11 };
	// const unsigned char HXDTTable2[16] =
	private static byte[] HXDTTable2 = new byte[] { 9, 11, 6, 5, 12, 7, 14, 2, 13, 3, 1, 15, 4, 8, 0, 10 };
	// const unsigned char HXETTable1[16] =
	private static byte[] HXETTable1 = new byte[] { 14, 10, 7, 9, 12, 3, 2, 5, 13, 0, 15, 1, 4, 8, 6, 11 };
	// const unsigned char HXETTable2[16] =
	private static byte[] HXETTable2 = new byte[] { 12, 8, 2, 13, 7, 6, 1, 3, 11, 5, 9, 15, 0, 4, 10, 14 };
	// const unsigned char HXPETable[64] =
	private static byte[] HXPETable = new byte[] { 55, 42, 10, 18, 24, 21, 44, 35, 2, 22, 56, 43, 27, 58, 9, 50, 6, 36,
			12, 61, 37, 38, 53, 16, 62, 3, 7, 4, 32, 20, 63, 25, 51, 52, 54, 33, 49, 19, 46, 29, 48, 31, 23, 30, 41, 28,
			13, 5, 40, 60, 39, 11, 15, 17, 1, 0, 57, 34, 59, 8, 47, 14, 45, 26 };

	// const unsigned char HXPDTable[64] =
	private static byte[] HXPDTable = new byte[] { 55, 54, 8, 25, 27, 47, 16, 26, 59, 14, 2, 51, 18, 46, 61, 52, 23, 53,
			3, 37, 29, 5, 9, 42, 4, 31, 63, 12, 45, 39, 43, 41, 28, 35, 57, 7, 17, 20, 21, 50, 48, 44, 1, 11, 6, 62, 38,
			60, 40, 36, 15, 32, 33, 22, 34, 0, 10, 56, 13, 58, 49, 19, 24, 30

	};

	/*************************************************************/

	/*************************************************************/

	/* Table - Binary */

	// const unsigned char binary[64] =
	private static byte[] binary = new byte[] { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1,
			0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0,
			1, 1, 1, 1 };

	/**********************************************************
	 * 
	 * 
	 * /********************************************************** 功能：STS算法
	 * 参数1：source 待转换的16进制数据 8bytes 参数2：dest 转换后的16进制数据 8bytes 参数3：inkey 密钥
	 * 8bytes 参数4：type 加密-1,解密-0
	 **********************************************************/
	private void STA(byte[] source, byte[] dest, byte[] key, boolean type) {
		byte[] inkey = new byte[8];
		// inkey = key;
		inkey = Arrays.copyOf(key, 8);
		// unsigned char buffer1[64],buffer2[64],kwork[64];
		// unsigned char tmp,tmp1,tmp2;
		// unsigned char i,j,k;
		byte[] buffer1 = new byte[64];
		byte[] buffer2 = new byte[64];
		byte[] kwork = new byte[64];
		byte tmp, tmp1, tmp2;
		byte i, j, k;
		// WDTCTL = WDT_ARST_1000;
		if (type) {
			for (i = 0; i < 8; i++)
				inkey[i] = (byte) (inkey[i] ^ 0xff);// 1反码
			// *(inkey+i) = *(inkey+i) ^ 0xff;//1反码

			// tmp1 = *inkey;//右循环12bits
			// tmp2 = *(inkey+1);
			tmp1 = inkey[0];// 右循环12bits
			tmp2 = inkey[1];
			for (i = 1; i < 7; i++) {
				// *(inkey+i-1) = (*(inkey+i) &0xf0) >> 4;
				// *(inkey+i-1) |= (*(inkey+i+1) &0x0f) << 4;
				inkey[i - 1] = (byte) ((inkey[i] & 0xf0) >> 4);
				inkey[i - 1] |= (byte) ((inkey[i + 1] & 0x0f) << 4);
			}
			/**
			 * (inkey+6) = (*(inkey+7) &0xf0) >> 4; (inkey+6) |= (tmp1 &0x0f) <<
			 * 4; (inkey+7) = (tmp1 &0xf0) >> 4; (inkey+7) |= (tmp2 &0x0f) << 4;
			 */
			inkey[6] = (byte) ((inkey[7] & 0xf0) >> 4);
			inkey[6] |= (byte) ((tmp1 & 0x0f) << 4);
			inkey[7] = (byte) ((tmp1 & 0xf0) >> 4);
			inkey[7] |= (byte) ((tmp2 & 0x0f) << 4);
		}

		for (i = 0; i < 8; i++)// 将8个字节数据分为64位，每位按1个字节存放
		{
			// tmp = *(source + i);
			tmp = source[i];
			for (j = 0; j < 8; j++) {
				if ((tmp & 0x01) == 1)
					buffer2[8 * i + j] = 1;
				else
					buffer2[8 * i + j] = 0;
				tmp >>= 1;
			}
		}

		for (i = 0; i < 8; i++) {
			// tmp = *(inkey + i);
			tmp = inkey[i];
			for (j = 0; j < 8; j++) {
				if ((tmp & 0x01) == 1)
					kwork[8 * i + j] = 1;
				else
					kwork[8 * i + j] = 0;
				tmp >>= 1;
			}
		}

		if (type) {
			for (k = 0; k < 16; k++) {
				for (i = 0; i < 16; i++)// substitution process
				{
					tmp = 0x00;
					for (j = 3; j > 0; j--)
						tmp = (byte) ((tmp + buffer2[4 * i + j]) * 2);
					tmp = (byte) (tmp + buffer2[4 * i]);

					if ((kwork[i * 4 + 3]) != 0) {
						// tmp = *(HXETTable2 + tmp);
						tmp = HXETTable2[tmp];
					} else {
						// tmp = *(HXETTable1 + tmp);
						tmp = HXETTable1[tmp];
					}

					buffer1[i * 4 + 3] = binary[0 + tmp * 4];// 译为二进制
					buffer1[i * 4 + 2] = binary[1 + tmp * 4];
					buffer1[i * 4 + 1] = binary[2 + tmp * 4];
					buffer1[i * 4] = binary[3 + tmp * 4];
				}

				for (i = 0; i < 64; i++)// Permutation process
				{
					buffer2[HXPETable[i]] = buffer1[i];
				}

				tmp = kwork[63];// 左移一位
				for (i = 63; i > 0; i--)
					kwork[i] = kwork[i - 1];
				kwork[0] = tmp;
			}
		} else {
			for (k = 0; k < 16; k++) {
				for (i = 0; i < 64; i++)// Permutation process
				{
					buffer1[HXPDTable[i]] = buffer2[i];
				}

				for (i = 0; i < 16; i++)// substitution process
				{
					tmp = 0x00;
					for (j = 3; j > 0; j--)
						tmp = (byte) ((tmp + buffer1[4 * i + j]) * 2);
					tmp = (byte) (tmp + buffer1[4 * i]);

					if ((kwork[i * 4]) != 0) {
						tmp = HXDTTable2[tmp];
					} else {
						tmp = HXDTTable1[tmp];
					}

					buffer2[i * 4 + 3] = binary[0 + tmp * 4];// 译为二进制
					buffer2[i * 4 + 2] = binary[1 + tmp * 4];
					buffer2[i * 4 + 1] = binary[2 + tmp * 4];
					buffer2[i * 4] = binary[3 + tmp * 4];
				}

				tmp = kwork[0];// 右移一位
				for (i = 0; i < 63; i++)
					kwork[i] = kwork[i + 1];
				kwork[63] = tmp;
			}
		}

		j = 0;
		for (i = 0; i < 8; i++) {
			dest[i] = 0x00;
			for (k = 7; k > 0; k--)
				dest[i] = (byte) ((dest[i] + buffer2[j + k]) * 2);

			dest[i] = (byte) (dest[i] + buffer2[j]);
			j += 8;
		}
	}

}
